package cn.lg.soar.system.biz.modules.auth.service.impl;

import cn.lg.soar.common.data.tree.ITreeResult;
import cn.lg.soar.common.util.AssertUtil;
import cn.lg.soar.common.util.current.CurrentProxy;
import cn.lg.soar.core.annotations.SoarCache;
import cn.lg.soar.core.annotations.SoarCacheEvict;
import cn.lg.soar.database.base.service.impl.TreeServiceImpl;
import cn.lg.soar.system.biz.config.SystemCacheKey;
import cn.lg.soar.system.biz.modules.auth.entity.PostRoleRel;
import cn.lg.soar.system.biz.modules.auth.entity.Role;
import cn.lg.soar.system.biz.modules.auth.entity.RoleMenuRel;
import cn.lg.soar.system.biz.modules.auth.entity.UserRoleRel;
import cn.lg.soar.system.biz.modules.auth.mapper.RoleMapper;
import cn.lg.soar.system.biz.modules.auth.model.RoleDto;
import cn.lg.soar.system.biz.modules.auth.model.RoleTree;
import cn.lg.soar.system.biz.modules.auth.service.IRoleService;
import cn.lg.soar.system.biz.modules.auth.service.PostRoleRelService;
import cn.lg.soar.system.biz.modules.auth.service.RoleMenuRelService;
import cn.lg.soar.system.biz.modules.auth.service.UserRoleRelService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author luguoxiang
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public class RoleServiceImpl extends TreeServiceImpl<Long, RoleMapper, Role> implements IRoleService, CurrentProxy<IRoleService> {

    @Autowired
    private RoleMenuRelService roleMenuRelService;
    @Autowired
    private UserRoleRelService userRoleRelService;
    @Autowired
    private PostRoleRelService postRoleRelService;


    @Cacheable(value = SystemCacheKey.ROLEID_TO_ROLE, key = "#p0")
    @Override
    public Role getById(Serializable id) {
        return super.getById(id);
    }

    @Override
    public List<Role> listByCodes(Collection<String> codes) {
        if (CollectionUtils.isEmpty(codes)) {
            return Collections.emptyList();
        }
        codes = codes.stream().distinct().collect(Collectors.toList());
        return this.list(
                Wrappers.<Role>lambdaQuery()
                        .select(Role::getId, Role::getCode, Role::getName)
                        .in(Role::getCode, codes)
        );
    }

    @Override
    public List<String> codesByIds(List<Long> roleIds) {
        if (CollectionUtils.isEmpty(roleIds)) {
            return Collections.emptyList();
        }
        List<RoleTree> tree = proxy().tree();
        List<String> codes = new ArrayList<>(roleIds.size());
        Set<Long> set = new HashSet<>(roleIds);
        roleIds.clear();
        tree.forEach(x -> {
            if (set.contains(x.getId())) {
                codes.add(x.getCode());
            }
        });
        set.clear();
        return codes;
    }

    @SoarCacheEvict(value = SystemCacheKey.TREE, key = "'role'")
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Long create(RoleDto data) {
        Role convert = data.toRole();
        AssertUtil.isTrue(this.save(convert), "创建角色失败");
        if (data.getMenuIds() != null) {
            roleMenuRelService.setRoleMenu(convert.getId(), data.getMenuIds());
        }
        return convert.getId();
    }

    @Caching(evict = {
            @CacheEvict(value = { SystemCacheKey.ROLEID_TO_ROLE}, key = "#p0.id")
    })
    @SoarCacheEvict(value = SystemCacheKey.TREE, key = "'role'")
    @Override
    public boolean updateById(Role entity) {
        return super.updateById(entity);
    }

    @Caching(evict = {
            @CacheEvict(value = { SystemCacheKey.ROLEID_TO_ROLE}, key = "#p0")
    })
    @SoarCacheEvict(value = SystemCacheKey.TREE, key = "'role'")
    @Override
    public boolean removeById(Serializable id) {
        return super.removeById(id);
    }

    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public boolean removeByIds(Collection<?> list) {
        IRoleService self = this.proxy();
        for (Object id : list) {
            AssertUtil.isTrue(self.removeById((Serializable) id), "删除{0}失败", id);
        }
        userRoleRelService.remove(Wrappers.<UserRoleRel>lambdaQuery().in(UserRoleRel::getRoleId, list));
        postRoleRelService.remove(Wrappers.<PostRoleRel>lambdaQuery().in(PostRoleRel::getRoleId, list));
        roleMenuRelService.remove(Wrappers.<RoleMenuRel>lambdaQuery().in(RoleMenuRel::getRoleId, list));
        return true;
    }

    @SoarCache(value = SystemCacheKey.TREE, key = "'role'")
    @Override
    public List<RoleTree> tree() {
        List<Role> list = list(
                Wrappers.<Role>lambdaQuery()
                        .select(
                                Role::getId,
                                Role::getParentId,
                                Role::getCode,
                                Role::getName,
                                Role::getType
                        )
                        .eq(Role::getDisabled, false)
        );
        return ITreeResult.valueOf(list, 0L, RoleTree::new);
    }

    @Caching(evict = {
            @CacheEvict(value = {
                    SystemCacheKey.ROLEID_TO_ROLE,
                    SystemCacheKey.USERID_TO_POSTS,
                    SystemCacheKey.USERID_TO_ROLEIDS,
                    SystemCacheKey.POSTID_TO_ROLEIDS,
                    SystemCacheKey.USERID_TO_ALL_ROLEIDS,
                    SystemCacheKey.ROLEID_TO_MENUIDS,
                    SystemCacheKey.MENUID_TO_PERMITS,
                    SystemCacheKey.ROLEID_TO_PERMITS,
            }, allEntries = true)
    })
    @SoarCacheEvict(value = SystemCacheKey.TREE, key = "'role'")
    @Override
    public void clearCache() {}

}
